﻿// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "CommandPattern.generated.h"

/**	命令模式 Command Pattern
 *	描述
 *		将一个请求封装为一个对象，从而使我们可用不同的请求对客户进行参数化；对请求排队或者记录请求日志，以及支持可撤销的操作。
 *		命令模式是一种对象行为型模式，其别名为动作(Action)模式或事务(Transaction)模式。
 *		建造者模式将客户端与包含多个组成部分的复杂对象的创建过程分离，客户端无需知道复杂对象的内部组成与装配方式，主需要知道所需的建造者即可。类似工厂方法，但是建造者模式返回一个完整的复杂产品，而抽象工厂模式则返回一系列相关的产品。以汽车为例，工厂方法可以看成不同汽车配件的生成，而建造者模式则可以看成时汽车的组装
 *	套路
 *		客户端 Client 
 *			命令的发起者。确定接下来要执行什么命令。
 *		调用者 Invoker
 *			命令的管理者，不关心每个命令具体是做什么内容，根据客户端的指示按序执行命令。
 *		抽象命令 Command
 *			命令接口协议，确定每个命令需要提供的功能，这里要求每个命令类都提供执行方法。
 *		具体命令 ConcreteCommand
 *			包含执行一个命令所需的所有上下文信息，例如执行接收者的哪个方法，以及方法所需要的参数，甚至命令作为GUI 显示时的相关信息，例如应该显示的图标路径。具体命令类是命令模式中的核心节点，需要重点理解。
 *		接收者 Receiver
 *			命令所对应任务的实际执行者，位于调用链条的末端。
 *	使用场景
 *		系统需要将请求调用者和请求接收者解耦，使得调用者和接收者不直接交互。
 *		系统需要在不同的时间指定请求、将请求排队和执行请求。
 *		系统需要将一组操作组合在一起，即支持宏命令
 *		示例
 *		按键、快捷键映射、玩家输入
 *		撤销(Undo)、恢复(Redo)，维护命令列表
 *		新手引导
 *	优缺点
 *		优点
 *			降低系统的耦合度。
 *			新的命令可以很容易地加入到系统中。
 *			可以比较容易地设计一个命令队列和宏命令（组合命令）。
 *			可以方便地实现对请求的Undo和Redo。
 *		缺点
 *			使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类，因此某些系统可能需要大量具体命令类，这将影响命令模式的使用。
 */

// 抽象接收者类 Receiver
UCLASS()
class MISCELLANEOUSPROJECT_API UCommandCmdReceiver : public UObject
{
	GENERATED_BODY()
public:

	virtual void Action()
	{
		check(0 && "You must override this");
	}
};

// 具体接收者类 Receiver —— 场景传送
UCLASS()
class MISCELLANEOUSPROJECT_API UCommandLevelPortal : public UCommandCmdReceiver
{
	GENERATED_BODY()
public:
	virtual void Action() override
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 传送到下一个场景"));
	}
};

// 具体接收者类 Receiver —— 资料片播放
UCLASS()
class MISCELLANEOUSPROJECT_API UCommandCutscene : public UCommandCmdReceiver
{
	GENERATED_BODY()
public:
	virtual void Action() override
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 播放剧情动画"));
	}
};

// 抽象命令类
UCLASS(Abstract)
class MISCELLANEOUSPROJECT_API UCommandCommand : public UObject
{
	GENERATED_BODY()
public:

	void SetReceiver(UCommandCmdReceiver* pCmdReceiver) { m_pCmdReceiver = pCmdReceiver; }

	// 调用接收者的 Action
	virtual void Execute()
	{
		if (m_pCmdReceiver)
		{
			m_pCmdReceiver->Action();
		}
	}

	// virtual void undo()

protected:
	UCommandCmdReceiver* m_pCmdReceiver;
};

// 具体命令类 —— 场景传送命令
UCLASS()
class MISCELLANEOUSPROJECT_API UCommandPortalCommand : public UCommandCommand
{
	GENERATED_BODY()
public:

	// 可重载做些额外的工作
	//virtual void Execute() override {  }
};

// 具体命令类 ——  资料片播放命令
UCLASS()
class MISCELLANEOUSPROJECT_API UCommandCutsceneCommand : public UCommandCommand
{
	GENERATED_BODY()
public:

	// 可重载做些额外的工作
	//virtual void Execute() override {  }
};

// 调用者 Invoker
UCLASS()
class MISCELLANEOUSPROJECT_API ACommandCommandActor : public AActor
{
	GENERATED_BODY()
public:

	virtual void BeginPlay() override
	{
		// 创建接收者 场景传送
		UCommandLevelPortal* LevelPortal = NewObject<UCommandLevelPortal>();

		// 创建命令对象
		UCommandPortalCommand* PortalCommand = NewObject<UCommandPortalCommand>();
		PortalCommand->SetReceiver(LevelPortal);

		// this 当做调用者 Invoker
		PortalCommand->Execute();

		// 创建接收者  资料片播放
		UCommandCutscene* Cutscene = NewObject<UCommandCutscene>();

		// 创建命令对象
		UCommandCutsceneCommand* CutsceneCommand = NewObject<UCommandCutsceneCommand>();
		CutsceneCommand->SetReceiver(Cutscene);

		// this 当做调用者 Invoker
		CutsceneCommand->Execute();
	}
};
